<!DOCTYPE html>
<html lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
  <meta charset="utf-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1">
<!-- Begin Jekyll SEO tag v2.7.1 -->
<title>Geo | 微光</title>
<meta name="generator" content="Jekyll v4.2.1">
<meta property="og:title" content="Geo">
<meta property="og:locale" content="en_US">
<meta name="description" content="Redis Geo 是对地球上按照经纬度定位的点的相关操作的抽象。">
<meta property="og:description" content="Redis Geo 是对地球上按照经纬度定位的点的相关操作的抽象。">
<link rel="canonical" href="/redis/data-type/geo.html">
<meta property="og:url" content="/redis/data-type/geo.html">
<meta property="og:site_name" content="微光">
<meta property="og:type" content="article">
<meta property="article:published_time" content="2022-01-18T01:52:04+08:00">
<meta name="twitter:card" content="summary">
<meta property="twitter:title" content="Geo">
<script type="application/ld+json">
{"description":"Redis Geo 是对地球上按照经纬度定位的点的相关操作的抽象。","url":"/redis/data-type/geo.html","headline":"Geo","dateModified":"2022-01-18T01:52:04+08:00","datePublished":"2022-01-18T01:52:04+08:00","@type":"BlogPosting","mainEntityOfPage":{"@type":"WebPage","@id":"/redis/data-type/geo.html"},"@context":"https://schema.org"}</script>
<!-- End Jekyll SEO tag -->
<link rel="stylesheet" href="/assets/css/normalize.css">
  <link rel="stylesheet" href="/assets/css/style.css">
<link type="application/atom+xml" rel="alternate" href="/feed.xml" title="微光">
</head>
<body>
<header class="site-header">

  <div class="wrapper">
<a class="site-title" rel="author" href="/">微光</a><nav class="site-nav">
        <input type="checkbox" id="nav-trigger" class="nav-trigger">
        <label for="nav-trigger">
          <span class="menu-icon">
            <svg viewbox="0 0 18 15" width="18px" height="15px">
              <path d="M18,1.484c0,0.82-0.665,1.484-1.484,1.484H1.484C0.665,2.969,0,2.304,0,1.484l0,0C0,0.665,0.665,0,1.484,0 h15.032C17.335,0,18,0.665,18,1.484L18,1.484z M18,7.516C18,8.335,17.335,9,16.516,9H1.484C0.665,9,0,8.335,0,7.516l0,0 c0-0.82,0.665-1.484,1.484-1.484h15.032C17.335,6.031,18,6.696,18,7.516L18,7.516z M18,13.516C18,14.335,17.335,15,16.516,15H1.484 C0.665,15,0,14.335,0,13.516l0,0c0-0.82,0.665-1.483,1.484-1.483h15.032C17.335,12.031,18,12.695,18,13.516L18,13.516z"></path>
            </svg>
          </span>
        </label>

        <div class="trigger">
<a class="page-link" href="/about/">About</a><a class="page-link" href="/doc/main">DocMain</a><a class="page-link" href="/sites.html">Sites</a>
</div>
      </nav>
</div>
</header>
<div class="x-collections-bar">
  <a href="/">Home</a>
  
    
      <a href="/algri/index">算法</a>
    
  
    
      <a href="/java/index">Java</a>
    
  
    
  
    
  
    
      <a href="/redis/index">Redis</a>
    
  
</div>

<div class="x-content-side-layout x-container">
  <div class="x-left">
    <h3>本文目录</h3>
    <ul id="toc" class="section-nav">
<li class="toc-entry toc-h2"><a href="#%E5%AD%98%E5%82%A8%E6%A8%A1%E5%9E%8B">存储模型</a></li>
<li class="toc-entry toc-h2"><a href="#%E4%BD%BF%E7%94%A8%E5%9C%BA%E6%99%AF">使用场景</a></li>
<li class="toc-entry toc-h2">
<a href="#%E5%9F%BA%E6%9C%AC%E5%91%BD%E4%BB%A4">基本命令</a>
<ul>
<li class="toc-entry toc-h3"><a href="#geoadd">GEOADD</a></li>
<li class="toc-entry toc-h3"><a href="#geodist">GEODIST</a></li>
<li class="toc-entry toc-h3"><a href="#geohash">GEOHASH</a></li>
<li class="toc-entry toc-h3"><a href="#geopos">GEOPOS</a></li>
<li class="toc-entry toc-h3"><a href="#%E7%A4%BA%E4%BE%8B">示例</a></li>
</ul>
</li>
<li class="toc-entry toc-h2">
<a href="#%E6%90%9C%E7%B4%A2%E5%91%BD%E4%BB%A4">搜索命令</a>
<ul>
<li class="toc-entry toc-h3"><a href="#geosearch">GEOSEARCH</a></li>
<li class="toc-entry toc-h3"><a href="#geosearchstore">GEOSEARCHSTORE</a></li>
<li class="toc-entry toc-h3"><a href="#georadius">GEORADIUS</a></li>
</ul>
</li>
</ul>
  </div>
  <div class="x-content">
    <h1><strong>Redis - Geo</strong></h1>
    <small>2022-01-18 01:52:04 +0800</small>
    
    <article class="x-article"><p>Redis Geo 是对地球上按照经纬度定位的点的相关操作的抽象。</p>

<h2 id="存储模型">
<a class="anchor" href="#%E5%AD%98%E5%82%A8%E6%A8%A1%E5%9E%8B" aria-hidden="true"><span class="octicon octicon-link"></span></a>存储模型</h2>

<ul>
  <li>经度的有效范围是 -180 到 180 度。</li>
  <li>纬度的有效分为是 -85.05112878 到 85.05112878 度。</li>
</ul>

<p>Redis 中，地理数据被存储在一个 sorted set 中，决定一个地点在 sorted set 中的 score 的方式是 <a href="https://en.wikipedia.org/wiki/Geohash">Geohash</a>，即把纬度和经度的 bit 交错排列构成一个 52 bit 的唯一整数。我们知道，sorted set 的双精度 score 可以容得下 52-bit 整数，所以没有经度丢失。</p>

<h2 id="使用场景">
<a class="anchor" href="#%E4%BD%BF%E7%94%A8%E5%9C%BA%E6%99%AF" aria-hidden="true"><span class="octicon octicon-link"></span></a>使用场景</h2>

<p>TODO:</p>

<h2 id="基本命令">
<a class="anchor" href="#%E5%9F%BA%E6%9C%AC%E5%91%BD%E4%BB%A4" aria-hidden="true"><span class="octicon octicon-link"></span></a>基本命令</h2>

<h3 id="geoadd">
<a class="anchor" href="#geoadd" aria-hidden="true"><span class="octicon octicon-link"></span></a><code class="language-plaintext highlighter-rouge">GEOADD</code>
</h3>

<p>把一些带有名称的经纬度点增加到一个 key 中：</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>GEOADD key [NX|XX] [CH] 经度 纬度 名称 [经度 纬度 名称 ...]
</code></pre></div></div>

<p>其中：</p>

<ul>
  <li>
<code class="language-plaintext highlighter-rouge">NX</code> 表示仅更新已存在的元素，而不是添加新元素</li>
  <li>
<code class="language-plaintext highlighter-rouge">XX</code> 表示不更新已存在的元素，仅添加新元素</li>
  <li>
<code class="language-plaintext highlighter-rouge">CH</code> 表示返回<em>新增加的元素</em>数量和<em>被修改的已存在的元素</em>数量的和。缺省此项，则仅返回新增加的元素的数量。</li>
</ul>

<p>从 3.2.0 版本加入。</p>

<h3 id="geodist">
<a class="anchor" href="#geodist" aria-hidden="true"><span class="octicon octicon-link"></span></a><code class="language-plaintext highlighter-rouge">GEODIST</code>
</h3>

<p>计算同一个 key 下的两个地点之间的距离：</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>GEODIST key 名称1 名称2 [M|KM|FT|MI]
</code></pre></div></div>

<p>后面四个是单位：</p>

<ul>
  <li>
<code class="language-plaintext highlighter-rouge">M</code> - meter - 米（缺省值）</li>
  <li>
<code class="language-plaintext highlighter-rouge">KM</code> - kilometer - 千米</li>
  <li>
<code class="language-plaintext highlighter-rouge">FT</code> - feet - 英尺</li>
  <li>
<code class="language-plaintext highlighter-rouge">MI</code> - mile - 英里</li>
</ul>

<p>从 3.2.0 版本加入。</p>

<h3 id="geohash">
<a class="anchor" href="#geohash" aria-hidden="true"><span class="octicon octicon-link"></span></a><code class="language-plaintext highlighter-rouge">GEOHASH</code>
</h3>

<p>获取一些地理位置的 GeoHash 值：</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>GEOHASH key 名称 [名称 ...]
</code></pre></div></div>

<p>从 3.2.0 版本加入。</p>

<h3 id="geopos">
<a class="anchor" href="#geopos" aria-hidden="true"><span class="octicon octicon-link"></span></a><code class="language-plaintext highlighter-rouge">GEOPOS</code>
</h3>

<p>获取一些地理位置的经纬度：</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>GEOPOS key 名称 [名称 ...]
</code></pre></div></div>

<p>从 3.2.0 版本加入。</p>

<h3 id="示例">
<a class="anchor" href="#%E7%A4%BA%E4%BE%8B" aria-hidden="true"><span class="octicon octicon-link"></span></a>示例</h3>

<div class="language-console highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="gp">redis&gt;</span><span class="w"> </span>GEOADD Sicily 13.361389 38.115556 <span class="s2">"Palermo"</span> 15.087269 37.502669 <span class="s2">"Catania"</span>
<span class="go">(integer) 2
</span><span class="gp">redis&gt;</span><span class="w"> </span>GEODIST Sicily Palermo Catania
<span class="go">"166274.1516"
</span><span class="gp">redis&gt;</span><span class="w"> </span>GEOHASH Sicily Palermo Catania
<span class="go">1) "sqc8b49rny0"
2) "sqdtr74hyu0"
</span><span class="gp">redis&gt;</span><span class="w"> </span>GEOPOS Sicily Palermo Catania NonExisting
<span class="go">1) 1) "13.36138933897018433"
   2) "38.11555639549629859"
2) 1) "15.08726745843887329"
   2) "37.50266842333162032"
3) (nil)
</span></code></pre></div></div>

<h2 id="搜索命令">
<a class="anchor" href="#%E6%90%9C%E7%B4%A2%E5%91%BD%E4%BB%A4" aria-hidden="true"><span class="octicon octicon-link"></span></a>搜索命令</h2>

<p>示例数据准备：</p>

<div class="language-console highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="gp">redis&gt;</span><span class="w"> </span>GEOADD Sicily 13.361389 38.115556 <span class="s2">"Palermo"</span> 15.087269 37.502669 <span class="s2">"Catania"</span>
<span class="go">(integer) 2
</span><span class="gp">redis&gt;</span><span class="w"> </span>GEOADD Sicily 12.758489 38.788135 <span class="s2">"edge1"</span> 17.241510 38.788135 <span class="s2">"edge2"</span>
<span class="go">(integer) 2
</span></code></pre></div></div>

<h3 id="geosearch">
<a class="anchor" href="#geosearch" aria-hidden="true"><span class="octicon octicon-link"></span></a><code class="language-plaintext highlighter-rouge">GEOSEARCH</code>
</h3>

<p>查询一个区域内（包括边界上）的地理位置点：</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>GEOSEARCH key
    [FROMMEMBER member] [FROMLONLAT longitude latitude]
    [BYRADIUS radius M|KM|FT|MI] [BYBOX width height M|KM|FT|MI]
    [ASC|DESC] [COUNT count [ANY]]
    [WITHCOORD] [WITHDIST] [WITHHASH]
</code></pre></div></div>

<ul>
  <li>中心点
    <ul>
      <li>
<code class="language-plaintext highlighter-rouge">FROMMEMBER</code> 中心点的名称</li>
      <li>
<code class="language-plaintext highlighter-rouge">FROMLONLAT</code> 中心点的经纬度</li>
    </ul>
  </li>
  <li>区域xingzhuang
    <ul>
      <li>
<code class="language-plaintext highlighter-rouge">BYRADIUS</code> 以中心点为圆心的圆形区域</li>
      <li>
<code class="language-plaintext highlighter-rouge">BYBOX</code> 以中心点位中心的矩形区域</li>
    </ul>
  </li>
  <li>排序
    <ul>
      <li>
<code class="language-plaintext highlighter-rouge">ASC</code> 按照距离中心点从近到远的顺序</li>
      <li>
<code class="language-plaintext highlighter-rouge">DESC</code> 按照距离中心点从远到近的顺序</li>
    </ul>
  </li>
  <li>返回数量
    <ul>
      <li>
<code class="language-plaintext highlighter-rouge">COUNT</code> 表示返回最前面几条。缺省则返回区域内的全部地理位置</li>
      <li>
<code class="language-plaintext highlighter-rouge">ANY</code> 存在时表示，尽可能快地返回指定数量的点，而不是等全部都算出来并排序后取最前面几个点</li>
    </ul>
  </li>
  <li>返回值
    <ul>
      <li>
<code class="language-plaintext highlighter-rouge">WITHDIST</code> 使返回值中带有距离中心点的距离</li>
      <li>
<code class="language-plaintext highlighter-rouge">WITHCOORD</code> 返回结果位置的坐标</li>
      <li>
<code class="language-plaintext highlighter-rouge">WITHHASH</code> 返回结果中带有 GeoHash 值</li>
    </ul>
  </li>
</ul>

<p>从版本 6.2.0 引入。</p>

<div class="language-console highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="gp">redis&gt;</span><span class="w"> </span>GEOSEARCH Sicily FROMLONLAT 15 37 BYRADIUS 200 km ASC
<span class="go">1) "Catania"
2) "Palermo"
</span><span class="gp">redis&gt;</span><span class="w"> </span>GEOSEARCH Sicily FROMLONLAT 15 37 BYBOX 400 400 km ASC WITHCOORD WITHDIST
<span class="go">1) 1) "Catania"
   2) "56.4413"
   3) 1) "15.08726745843887329"
      2) "37.50266842333162032"
2) 1) "Palermo"
   2) "190.4424"
   3) 1) "13.36138933897018433"
      2) "38.11555639549629859"
3) 1) "edge2"
   2) "279.7403"
   3) 1) "17.24151045083999634"
      2) "38.78813451624225195"
4) 1) "edge1"
   2) "279.7405"
   3) 1) "12.7584877610206604"
      2) "38.78813451624225195"
</span><span class="gp">redis&gt;</span><span class="w">
</span></code></pre></div></div>

<h3 id="geosearchstore">
<a class="anchor" href="#geosearchstore" aria-hidden="true"><span class="octicon octicon-link"></span></a><code class="language-plaintext highlighter-rouge">GEOSEARCHSTORE</code>
</h3>

<p>和 <code class="language-plaintext highlighter-rouge">GEOSEARCH</code> 类似，它把搜索结果存放到一个目标 key 中：</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>GEOSEARCHSTORE destination source
    [FROMMEMBER member] [FROMLONLAT longitude latitude]
    [BYRADIUS radius M|KM|FT|MI] [BYBOX width height M|KM|FT|MI]
    [ASC|DESC] [COUNT count [ANY]]
    [STOREDIST]
</code></pre></div></div>

<p>使用 <code class="language-plaintext highlighter-rouge">STOREDIST</code> 时，存到目标 key 中的数据是以距离中心点的距离作为 score 来排序。</p>

<p>从版本 6.2.0 引入。</p>

<div class="language-console highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="gp">redis&gt;</span><span class="w"> </span>GEOSEARCHSTORE key1 Sicily FROMLONLAT 15 37 BYBOX 400 400 km ASC COUNT 3
<span class="go">(integer) 3
</span><span class="gp">redis&gt;</span><span class="w"> </span>GEOSEARCH key1 FROMLONLAT 15 37 BYBOX 400 400 km ASC WITHCOORD WITHDIST WITHHASH
<span class="go">1) 1) "Catania"
   2) "56.4413"
   3) (integer) 3479447370796909
   4) 1) "15.08726745843887329"
      2) "37.50266842333162032"
2) 1) "Palermo"
   2) "190.4424"
   3) (integer) 3479099956230698
   4) 1) "13.36138933897018433"
      2) "38.11555639549629859"
3) 1) "edge2"
   2) "279.7403"
   3) (integer) 3481342659049484
   4) 1) "17.24151045083999634"
      2) "38.78813451624225195"
</span><span class="gp">redis&gt;</span><span class="w"> </span>GEOSEARCHSTORE key2 Sicily FROMLONLAT 15 37 BYBOX 400 400 km ASC COUNT 3 STOREDIST
<span class="go">(integer) 3
</span><span class="gp">redis&gt;</span><span class="w"> </span>ZRANGE key2 0 <span class="nt">-1</span> WITHSCORES
<span class="go">1) "Catania"
2) "56.441257870158204"
3) "Palermo"
4) "190.44242984775784"
5) "edge2"
6) "279.7403417843143"
</span></code></pre></div></div>

<h3 id="georadius">
<a class="anchor" href="#georadius" aria-hidden="true"><span class="octicon octicon-link"></span></a><code class="language-plaintext highlighter-rouge">GEORADIUS</code>
</h3>

<p>在 3.2.0 版本引入，在 6.2.0 版本废弃，推荐改用 <code class="language-plaintext highlighter-rouge">GEOSEARCH</code>。</p>

<p>查询一个圆形区域内的地理位置点，算是 <code class="language-plaintext highlighter-rouge">GEOSEARCH</code> 的一个弱化版。下面把相关命令也都列出来：</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>GEORADIUS key
    longitude latitude radius M|KM|FT|MI
    [WITHCOORD] [WITHDIST] [WITHHASH]
    [COUNT count [ANY]] [ASC|DESC]
    [STORE key] [STOREDIST key]

GEORADIUSBYMEMBER key
    member radius M|KM|FT|MI
    [WITHCOORD] [WITHDIST] [WITHHASH]
    [COUNT count [ANY]] [ASC|DESC]
    [STORE key] [STOREDIST key]
</code></pre></div></div>

<p><code class="language-plaintext highlighter-rouge">STORE</code> 是说把搜索结果存放到指定 key 中。</p>

<p><code class="language-plaintext highlighter-rouge">GEORADIUS_RO</code> 和 <code class="language-plaintext highlighter-rouge">GEORADIUSBYMEMBER_RO</code> 与不带 <code class="language-plaintext highlighter-rouge">_RO</code> 的两个命令的区别是不带有两个 <code class="language-plaintext highlighter-rouge">STORE</code> 参数，即只读版。</p>

</article>
  </div>
  <div class="x-right">
    <h3>Redis</h3>
    
      <div class="x-collection-section">
        <h4>开始</h4>
        
        <ol>
          
            
              <li><a href="/redis/index.html">开始</a></li>
            
          
            
              <li><a href="/redis/install.html">安装</a></li>
            
          
            
              <li><a href="/redis/concept.html">相关概念预览</a></li>
            
          
        </ol>
      </div>
    
      <div class="x-collection-section">
        <h4>数据类型</h4>
        
        <ol>
          
            
              <li><a href="/redis/data-type/key-and-string.html">Key 和 String</a></li>
            
          
            
              <li><a href="/redis/data-type/list.html">List</a></li>
            
          
            
              <li><a href="/redis/data-type/hash.html">Hash</a></li>
            
          
            
              <li><a href="/redis/data-type/set.html">Set</a></li>
            
          
            
              <li><a href="/redis/data-type/zset.html">Sorted Set</a></li>
            
          
            
              <li><a href="/redis/data-type/bitmap.html">Bitmap</a></li>
            
          
            
              <li><a href="/redis/data-type/hyperloglog.html">Hyperloglog</a></li>
            
          
            
              <li class="active"><a href="/redis/data-type/geo.html">Geo</a></li>
            
          
        </ol>
      </div>
    
      <div class="x-collection-section">
        <h4>其他特性</h4>
        
        <ol>
          
            
              <li><a href="/redis/feature/pipeline.html">流水线处理</a></li>
            
          
        </ol>
      </div>
    
      <div class="x-collection-section">
        <h4>持久化</h4>
        
        <ol>
          
            
              <li><a href="/redis/persist/durability.html">持久化在说什么</a></li>
            
          
            
              <li><a href="/redis/persist/rdb.html">快照（Snapshotting）</a></li>
            
          
            
              <li><a href="/redis/persist/aof.html">AOF</a></li>
            
          
        </ol>
      </div>
    
      <div class="x-collection-section">
        <h4>运维</h4>
        
        <ol>
          
            
              <li><a href="/redis/ops/persistence.html">持久化方案</a></li>
            
          
        </ol>
      </div>
    
      <div class="x-collection-section">
        <h4>应用场景</h4>
        
        <ol>
          
            
              <li><a href="/redis/usecase/blogs.html">应用场景相关文章</a></li>
            
          
        </ol>
      </div>
    
  </div>
</div>
<footer class="site-footer h-card">
  <data class="u-url" href="/"></data>

  <div class="wrapper">

    <div class="footer-col-wrapper">
      <div class="footer-col">
        <p class="feed-subscribe">
          <a href="/feed.xml">
            <svg class="svg-icon orange">
              <use xlink:href="/assets/social-icons.svg#rss"></use>
            </svg><span>Subscribe</span>
          </a>
        </p>
      </div>
      <div class="footer-col">
        <p>Write an awesome description for your new site here. You can edit this line in _config.yml. It will appear in your document head meta (for Google search results) and in your feed.xml site description.</p>
      </div>
    </div>

    <div class="social-links"></div>

  </div>

</footer>
</body>
</html>
